/************************************************************************************
**  
* @copyright (c) 2015-, duye Technology Co., LTD. All Right Reserved.
*
*************************************************************************************/
/**
* @file     duye_cap_http_analyser.cpp
* @version     
* @brief      
* @author   
* @date     2013-04-27
* @note 
*
*  1. 2018-04-27 created this file
* 
*/
#include <duye_logger.h>
#include <duye_cap_http_analyser.h>

static const int8* DUYE_LOG_PREFIX = "duye.cap.http.analyser";

namespace duye {

HttpAnalyserResult::HttpAnalyserResult()
	: m_isComplete(false) 
	, m_url(NULL)
	, m_status(NULL) {

}

HttpAnalyserResult::~HttpAnalyserResult() {
	clear();
}

void HttpAnalyserResult::clear() {
	m_isComplete = false;
	if (m_url) free(m_url);
	if (m_status) free(m_status);
	if (m_body.data) {
		free(m_body.data);
		m_body.len = 0;
	}

	HeaderPairList::iterator iter = m_headerPairList.begin();
	for (; iter != m_headerPairList.end(); ++iter) {
		if ((*iter).first) free((*iter).first);
		if ((*iter).second) free((*iter).second);
	}
}

HttpAnalyser::HttpAnalyser() : m_needReset(false) {
	m_parser.reset(HPT_REQUEST, this);
	m_parser.addListener(this);
}

HttpAnalyser::~HttpAnalyser() {}

int32 HttpAnalyser::analyse(const PacketReference& pkt, HttpAnalyserResult& result) {
	checkForReset();
	
	TcpHeader* tcpHeader = dynamic_cast<TcpHeader*>
		(const_cast<TfLayerHeader*>(pkt->getTfLayerHeader()));

	m_parser.parse(tcpHeader->getPayload(), tcpHeader->getPayloadLen());
	if (m_parser.getHttpParserData().getParserErrno() != HPE_OK) {
		HttpParserErrno err = m_parser.getHttpParserData().getParserErrno();

		DUYE_ERROR("http parse error(%d) : %s, %s.", 
			err, HttpParser::getErrnoName(err).c_str(), HttpParser::getErrnoDescription(err).c_str());

		m_needReset = true;
		return -1;
	}
	
	m_needReset = true;
	return 0;
}

int32 HttpAnalyser::analyse(const PacketReference& pkt, const TcpSession& session, HttpAnalyserResult& result) {
	// TODO:
	checkForReset();

	TcpHeader* tcpHeader = dynamic_cast<TcpHeader*>
		(const_cast<TfLayerHeader*>(pkt->getTfLayerHeader()));

	m_parser.parse(tcpHeader->getPayload(), tcpHeader->getPayloadLen());
	if (m_parser.getHttpParserData().getParserErrno() != HPE_OK) {
		HttpParserErrno err = m_parser.getHttpParserData().getParserErrno();
		DUYE_ERROR("http parse error(%d) : %s, %s.", 
			err, HttpParser::getErrnoName(err).c_str(), HttpParser::getErrnoDescription(err).c_str());

		m_needReset = true;
		return -1;
	}
	// m_needReset = true; // don't do this, in a session
	return 0;
}

int32 HttpAnalyser::onMessageBegin(HttpParserData* data) {
	return 0;
}

int32 HttpAnalyser::onUrl(HttpParserData* data, const uint8* url, int32 len) {
	m_result.m_url = (uint8*)malloc(len + 1);
	memcpy(m_result.m_url, url, len);
	m_result.m_url[len] = '\0';

	return 0;
}

int32 HttpAnalyser::onStatus(HttpParserData* data, const uint8* status, int32 len) {
	m_result.m_status = (uint8*)malloc(len + 1);
	memcpy(m_result.m_status, status, len);
	m_result.m_status[len] = '\0';

	return 0;
}

int32 HttpAnalyser::onHeaderField(HttpParserData* data, const uint8* headerField, int32 len) {
	if (m_tmpPair.first) {
		free(m_tmpPair.first);
		if (m_tmpPair.second) {
			free(m_tmpPair.second);
			m_tmpPair.second = NULL;
		}
	}

	m_tmpPair.first = (uint8* )malloc(len + 1);
	memcpy(m_tmpPair.first, headerField, len);
	m_tmpPair.first[len] = '\0';

	return 0;
}

int32 HttpAnalyser::onHeaderValue(HttpParserData* data, const uint8* headerValue, int32 len) {
	if (m_tmpPair.first == NULL) {
		DUYE_ERROR("m_tmpPair.first == NULL");
		return -1;
	}
	
	if (m_tmpPair.second == NULL) {
		DUYE_ERROR("m_tmpPair.second == NULL");
		return -1;
	}

	m_tmpPair.second = (uint8*)malloc(len + 1);
	memcpy(m_tmpPair.second, headerValue, len);
	m_tmpPair.second[len] = '\0';

	m_result.m_headerPairList.push_back(m_tmpPair);

	free(m_tmpPair.first);
	m_tmpPair.first = NULL;
	free(m_tmpPair.second);
	m_tmpPair.second = NULL;

	return 0;
}

int32 HttpAnalyser::onHeadersComplete(HttpParserData* data) {
	return 0;
}

int32 HttpAnalyser::onBody(HttpParserData* data, const uint8* body, int32 len) {
	// TODO: ~~~~~~~~~~~~~~~~~~~~~~~~~~!
	if (!m_result.m_body.data) {
		m_result.m_body.data = (uint8* )malloc(len);
		memcpy(m_result.m_body.data, body, len);
		m_result.m_body.len = len;
	} else {
		m_result.m_body.data = (uint8* )realloc(m_result.m_body.data, m_result.m_body.len);
		memcpy(m_result.m_body.data + m_result.m_body.len, body, len);
		m_result.m_body.len += len;
	}	

	return 0;
}

int32 HttpAnalyser::onMessageComplete(HttpParserData* data) {
	m_result.m_isComplete = true;
	m_needReset = true;
	return 0;
}

void HttpAnalyser::checkForReset() {
	if (m_needReset) {
		m_parser.reset(HPT_BOTH, this);

		if (m_tmpPair.first) {
			free(m_tmpPair.first);
			m_tmpPair.first = NULL;
		}

		if (m_tmpPair.second) {
			free(m_tmpPair.second);
			m_tmpPair.second = NULL;
		}
		
		m_result.clear();

		m_needReset = false;
	}
}

}
